package obj;

import data.DataHelper;
import jxl.CellView;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.read.biff.BiffException;
import jxl.write.*;
import jxl.write.Number;

import java.io.*;
import java.util.*;

public class Item implements Comparable<Item> {
    public static final String HEADER_BRAND = "Бренд";
    public static final String HEADER_PRODUCER = "Производитель";
    public static final String HEADER_MODEL = "Модель";
    public static final String HEADER_MODEL_LIST = "Список моделей телефонов";
    public static final String HEADER_PRICE = "Цена";
    public static final String HEADER_OLD_PRICE = "Старая цена";
    public static final String HEADER_COUNT = "Количество";
    public static final String HEADER_ARTICLE = "Артикул";

    public String article;
    public String name;
    public String brand;
    public String url;
    public List<String> models;
    public List<String> modelURLs;
    public Map<String, String> props = new HashMap<String, String>();
    public int price;
    public int oldPrice;
    public int count;

    public static List<Item> parseItemsXlsDir(String path, String... brands) throws IOException, BiffException {
        File pathFile = new File(path);
        List<Item> items = new ArrayList<Item>();
        if (pathFile.isDirectory()) {
            for (String brandFile : pathFile.list()) {
                if (brandFile.endsWith(".properties") || brandFile.endsWith(".svn")) {
                    continue;
                }
                if (isInBrandsList(brandFile, brands)) {
                    items.addAll(parseItemsXlsFile(path + brandFile));
                }
            }
        } else {
            items = parseItemsXlsDir(path);
        }
        return items;

    }

    public static boolean isInBrandsList(String brandFile, String[] brands) {
//        if (brands.length == 0) {
//            return true;
//        }
        if (brands.length == 0 || brands.length == 1 || brands[0].equals("All")) {
            return true;
        }
        for (String brand : brands) {
            if (brandFile.toLowerCase().contains(brand.toLowerCase())) {
                return true;
            } else if (brandFile.toLowerCase().contains("se") && brand.equalsIgnoreCase("sony ericsson")) {
                return true;
            }
        }
        return false;
    }

//    public static void main(String[] args) throws BiffException, IOException {
//        List<Item> items = parseItemsXlsFile("G:\\projects\\webasyst\\data\\extramobi\\accum\\accum.samsung.xls");
//        for (Item item : items) {
//            System.out.println(item);
//        }
//    }

    public static List<Item> parseItemsXlsFile(String path) throws IOException, BiffException {
        Workbook workbook = Workbook.getWorkbook(new File(path));
        List<Item> items = new ArrayList<Item>();
        Sheet sheet = workbook.getSheet(0);
        List<String> headerList = new ArrayList<String>();
        for (int row = 0; row < sheet.getRows(); row++) {
            Map<String, String> headerValue = new HashMap<String, String>(sheet.getColumns());
            for (int column = 0; column < sheet.getColumns(); column++) {
                String cell = sheet.getCell(column, row).getContents();
                if (row == 0) {
                    headerList.add(cell);
                } else {
                    headerValue.put(headerList.get(column), cell);
                }
            }
            if (row != 0 && headerList.contains(HEADER_BRAND)) {
                Item item = new Item();
                item.brand = headerValue.remove(HEADER_BRAND).trim();
                if (item.brand.trim().length() < 1) {
                    break; // trim empty rows
                }
                String model = headerValue.remove(HEADER_MODEL).trim();
                item.name = item.brand + " " + model;
                if (headerValue.containsKey(HEADER_MODEL_LIST)) { // body, ...
                    item.models = Arrays.asList(headerValue.remove(HEADER_MODEL_LIST).trim().split(","));
                }
                if (item.models != null && item.models.size() == 1) {
                    Item compatibleItem = searchCompatible(items, item.brand + " " + item.models.get(0));
                    if (compatibleItem != null) {
                        item.models = new ArrayList<String>(compatibleItem.models);
                    }
                }
                item.models = trimModels(item.models);
                item.price = Integer.parseInt(headerValue.remove(HEADER_PRICE).trim());
                item.oldPrice = Integer.parseInt(headerValue.remove(HEADER_OLD_PRICE).trim());
                item.count = Integer.parseInt(headerValue.remove(HEADER_COUNT).trim());
                item.article = headerValue.remove(HEADER_ARTICLE).trim();
                // properties
                item.props = headerValue;
                item.props.put(HEADER_MODEL, model);
                items.add(item);
            }
        }
        return items;
    }

    private static Item searchCompatible(List<Item> items, String name) {
        for (Item item : items) {
            if (item.name.equals(name)) {
                return item;
            }
        }
        return null;
    }

    public static void saveToXls(String path, List<Item> items) throws IOException, WriteException {
        File xlsFile = new File(path);
        WorkbookSettings s = new WorkbookSettings();
        s.setLocale(new Locale("ru", "RU"));
        WritableWorkbook workbook = Workbook.createWorkbook(xlsFile, s);
        WritableSheet sheet = workbook.createSheet("List 1", 0);
        // print header
        int column = 0;
        int row = 0;
        WritableCell cell = new Label(column++, row, HEADER_BRAND);
        sheet.addCell(cell);
        cell = new Label(column++, row, HEADER_MODEL);
        sheet.addCell(cell);
        boolean withModels = items.get(0).models != null;
        if (withModels) {
            cell = new Label(column++, row, HEADER_MODEL_LIST);
            sheet.addCell(cell);
        }
        cell = new Label(column++, row, HEADER_PRICE);
        sheet.addCell(cell);
        cell = new Label(column++, row, HEADER_OLD_PRICE);
        sheet.addCell(cell);
        cell = new Label(column++, row, HEADER_COUNT);
        sheet.addCell(cell);
        cell = new Label(column, row, HEADER_ARTICLE);
        sheet.addCell(cell);
        setColumnStyle(sheet, 0, true, false);
        setColumnStyle(sheet, 1, true, true);
        setColumnStyle(sheet, 2, true, true);
        setColumnStyle(sheet, 5, true, true);
        // print items
        for (Item item : items) {
            column = 0;
            ++row;
            cell = new Label(column++, row, item.brand);
            sheet.addCell(cell);
            cell = new Label(column++, row, item.name);
            sheet.addCell(cell);
            if (withModels) {
                cell = new Label(column++, row, toCSV(item.models));
                sheet.addCell(cell);
            }
            cell = new Number(column++, row, item.price);
            sheet.addCell(cell);
            cell = new Number(column++, row, item.oldPrice);
            sheet.addCell(cell);
            cell = new Number(column++, row, item.count);
            sheet.addCell(cell);
            cell = new Label(column, row, item.article);
            sheet.addCell(cell);
        }
        workbook.write();
        workbook.close();
    }

    private static void setColumnStyle(WritableSheet sheet, int column, boolean autoSize, boolean bold) {
        CellView columnView = sheet.getColumnView(column);
        WritableCellFormat cf;
        if (bold) {
            WritableFont font = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD);
            cf = new WritableCellFormat(font);
        } else {
            cf = new WritableCellFormat();
        }
        columnView.setFormat(cf);
        columnView.setAutosize(autoSize);
        sheet.setColumnView(column, columnView);
    }

    private static String toCSV(List<String> models) {
        StringBuilder buf = new StringBuilder();
        for (String model : models) {
            buf.append(",").append(model);
        }
        buf.delete(0, 1);
        return buf.toString();
    }

    private static List<String> trimModels(List<String> models) {
        if (models == null) {
            return null;
        }
        List<String> trimModels = new ArrayList<String>();
        for (String model : models) {
            trimModels.add(model.trim());
        }
        return trimModels;
    }

/*
    public static List<Item> parseBrandItems(String path) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(path));
        List<Item> items = new ArrayList<Item>();
        String line;
        while ((line = reader.readLine()) != null) {
            if (line.trim().length() < 1) {
                continue;
            }
            Item item = Item.parseItem(line);
            items.add(item);
        }
        reader.close();
        return items;
    }
*/

    public static Map<String, List<Item>> parseRemontItemsByBrand(String path) throws BiffException, IOException {
        List<Item> items = parseRemontItems(path);
        Map<String, List<Item>> itemsByBrand = new HashMap<String, List<Item>>();
        for (Item item : items) {
            String brand = item.brand;
            List<Item> itemsList;
            if (itemsByBrand.containsKey(brand)) {
                itemsList = itemsByBrand.get(brand);
                if (!itemsList.contains(item)) {
                    itemsList.add(item);
                }
            } else {
                itemsList = new ArrayList<Item>();
                itemsList.add(item);
            }
            itemsByBrand.put(brand, itemsList);
        }
        return itemsByBrand;
    }

    public static List<Item> parseRemontItems(String path) throws BiffException, IOException {
        Workbook workbook = Workbook.getWorkbook(new File(path));
        Sheet sheet = workbook.getSheet(0);
        List<Item> items = new ArrayList<Item>();
        for (int j = 0; j < Integer.MAX_VALUE; j++) {
            String brand;
            try {
                brand = sheet.getCell(j, 0).getContents();
            } catch (ArrayIndexOutOfBoundsException e) {
                break;
            }
            if (brand.length() == 0) {
                break;
            }
//            List<String> models = new ArrayList<String>();
            for (int i = 1; i < Integer.MAX_VALUE; i++) {
                Item item = new Item();
                item.brand = brand;
                item.article = "";
                item.price = 0;
                item.oldPrice = 200;
                item.count = 100;
                String model;
                try {
                    model = sheet.getCell(j, i).getContents();
                    item.name = brand + " " + model;
                } catch (ArrayIndexOutOfBoundsException e) {
                    break;
                }
                if (model.length() == 0) {
                    break;
                }
                items.add(item);
//                models.add(model);
            }
//            item.models = models;
        }
        Collections.sort(items);
        workbook.close();
        return items;
    }

/*
    public static Item parseItem(String line) {
        try {
            Item item = new Item();
            String fields[] = line.split(";");
            if (fields.length == 6) { //bodies
                item.name = fields[0];
                item.brand = fields[1];
                item.price = Integer.parseInt(fields[2]);
                item.oldPrice = Integer.parseInt(fields[3]);
                item.count = Integer.parseInt(fields[4]);
                item.article = fields[5].trim();
            } else if (fields.length == 8) { // chargers
                item.props = new HashMap<String, String>();
                item.name = fields[0];
                item.models = parseModels(fields[1]);
                item.brand = fields[2];
                item.price = Integer.parseInt(fields[4]);
                item.oldPrice = Integer.parseInt(fields[5]);
                item.count = Integer.parseInt(fields[6]);
                item.article = fields[7].trim();
                item.props.put("Производитель", fields[2]);
                item.props.put("Модель", fields[3]);
            } else if (fields.length == 10) { // headsets
                item.props = new HashMap<String, String>();
                item.name = fields[0];
                item.models = parseModels(fields[1]);
                item.brand = fields[2];
                item.props.put("Производитель", fields[2]);
                item.props.put("Модель", fields[3]);
                item.props.put("Тип", fields[4]);
                item.props.put("Разъем", fields[5]);
                item.price = Integer.parseInt(fields[6]);
                item.oldPrice = Integer.parseInt(fields[7]);
                item.count = Integer.parseInt(fields[8]);
                item.article = fields[9].trim();
            } else if (fields.length == 11) { // accums
                item.props = new HashMap<String, String>();
                item.name = fields[0];
                item.models = parseModels(fields[1]);
                item.brand = fields[2];
                item.props.put("Производитель", fields[2]);
                item.props.put("Модель", fields[3]);
                item.props.put("Емкость", fields[4]);
                item.props.put("Тип", fields[5]);
                item.props.put("Напряжение", fields[6]);
                item.price = Integer.parseInt(fields[7]);
                item.oldPrice = Integer.parseInt(fields[8]);
                item.count = Integer.parseInt(fields[9]);
                item.article = fields[10].trim();
            } else {
                throw new IllegalArgumentException("Unknown line type: " + line);
            }
            return item;
        } catch (Exception e) {
            throw new RuntimeException("Exception in line: " + line, e);
        }
    }
*/

    private static List<String> parseModels(String field) {
        String[] models = field.split(",");
        return Arrays.asList(models);
    }

    @Override
    public String toString() {
        return "Item{" +
                "article='" + article + '\'' +
                ", name='" + name + '\'' +
                ", brand='" + brand + '\'' +
                ", price=" + price +
                ", oldPrice=" + oldPrice +
                ", count=" + count +
                ", models=" + models +
                ", props=" + props +
                '}';
    }

    public int compareTo(Item item) {
        return brand.compareTo(item.brand);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Item item = (Item) o;

        if (article != null ? !article.equals(item.article) : item.article != null) return false;
        if (brand != null ? !brand.equals(item.brand) : item.brand != null) return false;
        if (name != null ? !name.equals(item.name) : item.name != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = article != null ? article.hashCode() : 0;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + (brand != null ? brand.hashCode() : 0);
        return result;
    }

//    public static List<Item> parseItemsDir(String path) throws BiffException, IOException {
//
//    }

    public static List<Item> parseAllItemsDir(String path) throws BiffException, IOException {
        File folder = new File(path);
        List<Item> allItems = new ArrayList<Item>();
        List<String> uniqueArticles = new ArrayList<String>();
        for (File dir : folder.listFiles()) {
            if (dir.isDirectory() && !dir.getName().contains(".svn")) {
                String dirPath = path + dir.getName() + "/";
                String propsFile = dirPath + dir.getName() + ".properties";
                Map<String, String> props = DataHelper.readProps(propsFile);
                String itemName = props.get("item.name");
                List<Item> itemsByDir = parseItemsXlsDir(dirPath, "All");
                filterItems(itemsByDir, itemName, uniqueArticles);
                allItems.addAll(itemsByDir);
            }
        }
        return allItems;
    }

    private static void filterItems(List<Item> itemsByDir, String itemName, List<String> uniqueArticles) {
        for (Item item : itemsByDir) {
            item.name = itemName.replace("${item.name}", item.name);
            if (item.article.equals("1600001")) {
                System.out.println(item);
            }
            if (uniqueArticles.contains(item.article)) {
                throw new IllegalArgumentException(item + " duplicate article!");
            } else {
                uniqueArticles.add(item.article);
            }
        }
    }
}
